package com.gp.billsrecord.ui.main.fragments

import android.graphics.Color
import android.graphics.Typeface
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
import com.afollestad.materialdialogs.list.listItemsMultiChoice
import com.github.mikephil.charting.animation.Easing
import com.github.mikephil.charting.components.Legend
import com.github.mikephil.charting.data.PieData
import com.github.mikephil.charting.data.PieDataSet
import com.github.mikephil.charting.data.PieEntry
import com.github.mikephil.charting.formatter.PercentFormatter
import com.github.mikephil.charting.utils.ColorTemplate
import com.google.android.material.tabs.TabLayoutMediator
import com.gp.billsrecord.databinding.FragmentMainChartBinding
import com.gp.billsrecord.base.BaseFragment
import com.gp.billsrecord.databinding.FragmentBarChartBinding
import com.gp.billsrecord.databinding.FragmentPieChartBinding
import com.gp.billsrecord.extensions.toMoney
import com.gp.billsrecord.model.data.BarChartInfo
import com.gp.billsrecord.model.data.BillFlowInfo
import com.gp.billsrecord.model.data.ConsumptionType
import com.gp.billsrecord.ui.main.adapters.BarChartAdapter
import com.gp.billsrecord.util.DateUtil
import com.gp.billsrecord.vm.AppViewModel
import com.loper7.date_time_picker.DateTimeConfig
import com.loper7.date_time_picker.dialog.CardDatePickerDialog
import java.lang.RuntimeException
import java.util.concurrent.atomic.AtomicLong
import kotlin.math.roundToInt

/*图表*/
class ChartFragment : BaseFragment<FragmentMainChartBinding>() {
    private val viewModel by viewModels<AppViewModel>()
    private val tabTitles = arrayOf("条形图", "饼图")
    private val timeMs = AtomicLong()
    private val consumeTypes = arrayListOf<ConsumptionType>()
    private val consumeSelectList = arrayListOf<Int>()
    override fun onBindingCreated() {
        binding.tvChartFilter.setOnClickListener {
            //选择筛选类型
            doTypeSelect()
        }
        binding.tvChartDateRange.setOnClickListener {
            //选择日期范围
            doDateSelect()
        }
        binding.vpChartType.adapter = object : FragmentStateAdapter(this) {
            override fun getItemCount(): Int = tabTitles.size

            override fun createFragment(position: Int): Fragment = when (position) {
                0 -> BarChartFragment()
                1 -> PieChartFragment()
                else -> throw RuntimeException("")
            }
        }
        TabLayoutMediator(binding.tabsChartType, binding.vpChartType) { tab, position ->
            tab.text = tabTitles[position]
        }.attach()
    }

    private fun doTypeSelect() {
        val itms = consumeTypes.map { it.typeName }
        val index = consumeSelectList.toIntArray()
        //筛选条件
        MaterialDialog(requireContext(), BottomSheet()).show {
            listItemsMultiChoice(
                items = itms,
                initialSelection = index,
                waitForPositiveButton = true,
                allowEmptySelection = true
            ) { _, indices, _ ->
                consumeSelectList.clear()
                consumeSelectList.addAll(indices.toList())
                doFilter()
            }
            positiveButton {}
        }
    }

    private fun doDateSelect() {
        //日期选择
        CardDatePickerDialog.builder(requireContext())
            .setTitle("日期选择")
            .setOnChoose {
                //日期选中
                timeMs.set(it)
                binding.tvChartDateRange.text = DateUtil.formatDateTime(it, "YYYY年MM月")
                doFilter()
            }
            .setWrapSelectorWheel(false)
            .setMaxTime(System.currentTimeMillis())
            .setDisplayType(DateTimeConfig.YEAR, DateTimeConfig.MONTH)
            .showFocusDateInfo(false)
            .showBackNow(false)
            .build()
            .show()
    }


    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        viewModel.observeConsumptionTypes().observe(viewLifecycleOwner) {
            consumeTypes.clear()
            consumeTypes.addAll(it)
        }
        //获取流水数据
        viewModel.chartBillFlows.observe(viewLifecycleOwner) {
            //支出、收入
            var income = 0L
            var outPay = 0L
            var number = 0
            it.forEach { billFlow ->
                number++
                if (billFlow.isIncome) {
                    income += billFlow.money
                } else {
                    outPay += billFlow.money
                }
            }
            binding.tvSummary.text = "共${number}笔,支出${outPay.toMoney()},收入${income.toMoney()}"
        }
        timeMs.set(System.currentTimeMillis())
        binding.tvChartDateRange.text = DateUtil.formatDateTime(timeMs.get(), "YYYY年MM月")
        doFilter()
    }

    private fun doFilter() {
        val types = consumeSelectList.map { consumeTypes[it].typeId }
        viewModel.doBillFlowFilterAsList(timeMs.get(), types)
    }
}

class PieChartFragment : BaseFragment<FragmentPieChartBinding>() {
    private val regularTTF by lazy {
        Typeface.createFromAsset(
            requireContext().assets,
            "OpenSans-Regular.ttf"
        )
    }
    private val lightTTF by lazy {
        Typeface.createFromAsset(
            requireContext().assets,
            "OpenSans-Light.ttf"
        )
    }
    private val viewModel by viewModels<AppViewModel>({ parentFragment ?: this })

    override fun onBindingCreated() {
        binding.pieChart.apply {
            setUsePercentValues(true)
            description.isEnabled = false
            setExtraOffsets(5F, 10F, 5F, 5F)
            dragDecelerationFrictionCoef = 0.95F
            setCenterTextTypeface(lightTTF)
            centerText = "支出分析"

            setExtraOffsets(20F, 0F, 20F, 0F)
            isDrawHoleEnabled = true
            setHoleColor(Color.WHITE)

            setTransparentCircleColor(Color.WHITE)
            setTransparentCircleAlpha(110)

            holeRadius = 58F
            transparentCircleRadius = 61F

            setDrawCenterText(true)

            rotationAngle = 0F
            isRotationEnabled = true
            isHighlightPerTapEnabled = true

            animateY(1400, Easing.EaseInOutQuad)

            legend.apply {
                verticalAlignment = Legend.LegendVerticalAlignment.TOP
                horizontalAlignment = Legend.LegendHorizontalAlignment.RIGHT
                orientation = Legend.LegendOrientation.VERTICAL
                setDrawInside(false)
                isEnabled = false
            }
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        viewModel.chartBillFlows.observe(viewLifecycleOwner) {
            initData(convertToPieEntries(it))
        }
    }

    /**
     * 处理数据
     */
    private fun convertToPieEntries(list: List<BillFlowInfo>?): List<PieEntry> {
        if (list.isNullOrEmpty()) return emptyList()
        //按消费类型分组
        val dataMapping = list.groupBy { it.type }
        val entries = arrayListOf<PieEntry>()
        var sum = 0F
        dataMapping.entries.forEach { entity ->
            val typeName = entity.key
            var balance = 0L
            //当前分组内的总金额
            entity.value.forEach { balance += it.money }
            sum += balance
            entries.add(PieEntry(balance.toFloat(), typeName))
        }
        return entries
    }

    private fun initData(entries: List<PieEntry>) {
        val colors = arrayListOf<Int>().apply {
            addAll(ColorTemplate.COLORFUL_COLORS.toTypedArray())
            addAll(ColorTemplate.JOYFUL_COLORS.toTypedArray())
            addAll(ColorTemplate.COLORFUL_COLORS.toTypedArray())
            addAll(ColorTemplate.LIBERTY_COLORS.toTypedArray())
            addAll(ColorTemplate.PASTEL_COLORS.toTypedArray())
        }
        val dataSet = PieDataSet(entries, "label").apply {
            sliceSpace = 3F
            selectionShift = 5F

            setColors(colors)

            valueLinePart1OffsetPercentage = 80F
            valueLinePart1Length = 0.2F
            valueLinePart2Length = 0.4F

            yValuePosition = PieDataSet.ValuePosition.OUTSIDE_SLICE
        }

        val pieData = PieData(dataSet).apply {
            setValueFormatter(PercentFormatter())
            setValueTextSize(11F)
            setValueTextColor(Color.BLACK)
            setValueTypeface(regularTTF)
        }
        binding.pieChart.apply {
            data = pieData
            highlightValues(null)
            invalidate()
        }
    }
}

/**
 * 条形图
 */
class BarChartFragment : BaseFragment<FragmentBarChartBinding>() {
    private val barChartAdapter = BarChartAdapter()
    private val viewModel by viewModels<AppViewModel>({ parentFragment ?: this })

    override fun onBindingCreated() {
        binding.rvBarChart.also { recyclerView ->
            recyclerView.layoutManager = LinearLayoutManager(requireContext())
            recyclerView.adapter = barChartAdapter
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        viewModel.chartBillFlows.observe(viewLifecycleOwner) {
            Log.i(TAG, "chartBillFlows: ${it.joinToString()}")
            val barList = convertToBarList(it)
            barChartAdapter.updateList(barList)
        }
    }

    /**
     *处理流水数据
     */
    private fun convertToBarList(list: List<BillFlowInfo>): List<BarChartInfo> {
        if (list.isNullOrEmpty()) return emptyList()
        //根据消费类型做分组
        val dataMapping = list.groupBy { it.type }
        val barList = arrayListOf<BarChartInfo>()
        var sum = 0F
        //分组后的数据各自算总数
        dataMapping.entries.forEach { entity ->
            val typeName = entity.key
            var balance = 0L
            entity.value.forEach { balance += it.money }
            sum += balance
            barList.add(BarChartInfo(typeName, 0, balance))
        }
        //根据每种类型的总金额算出占比
        barList.forEach { it.progress = it.balance.div(sum).times(100).roundToInt() }
        return barList
    }
}
